package com.test.springdata.repositories;

import com.test.springdata.dao.PersonDao;
import com.test.springdata.entities.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.Date;
import java.util.List;

/**
 * @author lzy
 * @version v1.0
 * Create DateTime: 2018/10/25 16:51
 * <p>
 * 1.Repository是一个空接口，即是一个标记接口
 * 2.若我们定义的接口继承了Repository,则该接口会被IOC容器识别为一个Repository Bean
 * 纳入到IOC容器中，进而可以在该接口中定义满足一定规则的方法
 * 3.实际上也可以通过注解@RepositoryDefinition注解来替代Repository接口实现
 * <p>
 * 在Repository子接口中声明方法：
 * 1.不是随便声明的，需要符合一定的规范
 * 2.查询方法以find|read|get开头，
 * 3.涉及条件查询时，条件的属性用条件关键字连接，
 * 4.需要注意的是：条件属性以首字母大写。
 * 5.支持属性的级联查询，若当前类有符合条件的属性，则优先使用，而不使用级联属性
 * 若需要使用级联属性，则属性之间使用_连接
 *
 * JpaRepository中提供的分页查询无法提供带有查询条件的分页查询，为了实现带有查询条件的分页查询，需要继承JpaSpecificationExecutor<>接口
 */
//@RepositoryDefinition(domainClass = Person.class, idClass = Integer.class)
public interface PersonRepository extends JpaRepository<Person, Integer>, JpaSpecificationExecutor<Person>, PersonDao {

    //根据lastName来获取对应的person对象
    Person getByLastName(String lastName);

    //WHERE lastName LIKE ?% and id<?
    List<Person> getByLastNameStartingWithAndIdLessThan(String lastName, Integer id);

    //WHERE lastName LIKE %? and id<?
    List<Person> getByLastNameEndingWithAndIdLessThan(String lastName, Integer id);

    //WHERE email IN (?,?,?) OR birth<?
    List<Person> getByEmailInOrBirthLessThan(List<String> emails, Date birth);

    //WHERE a.id>?
    List<Person> getByAddress_IdGreaterThan(Integer id);

    //查询id值最大的那个Person
    //使用 @Query可以自定义JPQL语句以实现更灵活的查询
    @Query("SELECT p FROM Person p where p.id = (select max(p2.id) from Person  p2)")
    Person getMaxIdPerson();

    //为query注解传递参数的方式1：使用占位符的方式
    @Query("select p from Person p where p.lastName=?1 and p.email=?2")
    List<Person> testQueryAnnotationParams1(String lastName, String email);

    //为query注解传递参数的方式1：使用命名参数的方式
    @Query("select p from Person p where p.lastName=:lastName and p.email=:email")
    List<Person> testQueryAnnotationParams2(@Param("email") String email, @Param("lastName") String lastName);

    //SpringData允许在占位符上添加%
    @Query("select p from Person p where p.lastName like %?1% or p.email like %?2%")
    List<Person> testQueryAnnotationLikeParam(String lastName, String email);

    //SpringData允许在占位符上添加%
    @Query("select p from Person p where p.lastName like %:lastName% or p.email like %:email%")
    List<Person> testQueryAnnotationLikeParam2(@Param("email") String email, @Param("lastName") String lastName);

    //设置nativeQuery = true即可以使用原生的sql查询
    @Query(value = "select count(*) from springdata_person", nativeQuery = true)
    long getTotalCount();

    //可以通过自定义的JPQL完成UPDATE和DELETE操作，注意JPQL不支持使用INSERT
    //在Query注解中编写jpql语句，但必须使用@Modifying进行修饰，以通知SpringData，这是一个UPDATE或DELETE操作
    //UPDATE或DELETE操作需要使用事务，此时需要定义service层，在service层的方法上添加事务操作
    //默认情况下SpringData的每个方法上有事务，但都是一个只读事务，它们不能完成修改操作
    @Modifying
    @Query("update Person p set p.email=:email where p.id=:id")
    void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);
}
